package util

import (
	"bufio"
	"bytes"
	"errors"
	"io"
	"math"
)

func Int32ToBytes(i32 int32) [4]byte {
	var lenArr [4]byte
	for i := 0; i < 4; i++ {
		lenArr[i] = byte((i32 >> ((3 - i) * 8)) & 0xFF)
	}
	return lenArr
}
func BytesToInt32(bs [4]byte) int32 {
	var i32 int32
	for i, b := range bs {
		i32 |= int32(b) << ((3 - i) * 8)
	}
	return i32
}

type DataPkgWriter struct {
	len  int
	data []byte
}

func BuildDataPkgWriter(data []byte) *DataPkgWriter {
	return &DataPkgWriter{
		len:  len(data),
		data: data,
	}
}

func (d *DataPkgWriter) Reset(data []byte) *DataPkgWriter {
	d.len = len(data)
	d.data = data
	return d
}

func (d DataPkgWriter) WriteTo(w io.Writer) (written int64, err error) {
	if d.len > math.MaxInt32-4 {
		err = errors.New("data.len needs less then maxInt32 - 4")
		return
	}
	i32Bytes := Int32ToBytes(int32(d.len))
	_, err = w.Write(i32Bytes[:])
	if err != nil {
		return 0, err
	}
	write, err := w.Write(d.data)
	written = int64(write)
	return
}

type DataPkgReader struct {
	reader *bufio.Reader
	remain *bytes.Buffer
}

func NewDataPkgReader(reader *bufio.Reader) *DataPkgReader {
	return &DataPkgReader{
		reader: reader,
		remain: &bytes.Buffer{},
	}
}

func (drp *DataPkgReader) Read(buf []byte) (int, error) {
	if drp.remain.Len() > 0 {
		read, err := drp.remain.Read(buf)
		if drp.remain.Len() == 0 {
			drp.remain.Reset()
		}
		return read, err
	} else {
		return drp.reader.Read(buf)
	}
}

func (drp *DataPkgReader) ReadByte() (byte, error) {
	//log.Printf("remain: %d", drp.remain.Len())
	if drp.remain.Len() > 0 {
		//log.Println("read remain")
		readByte, err := drp.remain.ReadByte()
		if drp.remain.Len() == 0 {
			drp.remain.Reset()
		}
		return readByte, err
	} else {
		//log.Println("read conn")
		return drp.reader.ReadByte()
	}
}

func (dpr *DataPkgReader) ReadOnePkg() ([]byte, error) {
	var lenArr [4]byte
	for i, _ := range lenArr {
		readByte, err := dpr.ReadByte()
		//log.Printf("readByte: %d", readByte)
		if err != nil {
			return nil, err
		}
		lenArr[i] = readByte
	}
	length := BytesToInt32(lenArr)
	var offset int32 = 0
	bufArr := make([]byte, length)
	tempBuf := make([]byte, 1200)
	for offset < length {
		read, err := dpr.Read(tempBuf)
		if err != nil {
			return nil, err
		}
		remain := offset + int32(read) - length
		if remain > 0 {
			//读出数据存在余量,需要将多余的数据写入到余量缓冲等待下次调用时读取
			dpr.remain.Write(tempBuf[read-int(remain) : read])
			copy(bufArr[offset:], tempBuf[:read-int(remain)])
			offset += int32(read) - remain
		} else {
			copy(bufArr[offset:], tempBuf[:read])
			offset += int32(read)
		}
	}
	return bufArr, nil
}
